package utils

import (
	"time"
	"github.com/wanhuo/GoSocketFrame/common"
	"sync"
)

type TimerRunType int

var (
	Timer_RunUnkown TimerRunType = -1 //无效定时器
	Timer_RunOnce   TimerRunType = 0  //定时器运行一次
	Timer_RunLoop   TimerRunType = 1  //定时器循环运行
)

//暂时这样写，回头使用小根堆减少线程数量
type Timer struct {
	exit      chan int
	duration  time.Duration
	userData  int
	timer     common.ITimer
	isWaiting bool
	runType   TimerRunType
	wg        sync.WaitGroup
	exitMutex sync.Mutex
	log       *Logger
	mytimer   *time.Timer
}

//重置到期时间,默认方式是为RunLoop
func (self *Timer) ResetTimerDuration(timeDur time.Duration) {
	self.duration = timeDur
	if self.isWaiting {
		self.Reset()
	} else {
		self.Start(Timer_RunLoop)
	}

}

//重置到期时间,默认方式是为RunLoop
func (self *Timer) ResetTimerAndRunOnce(timeDur time.Duration) {
	self.duration = timeDur
	if self.isWaiting {
		self.Stop()
	}
	self.Start(Timer_RunOnce)
}

func (self *Timer) Start(runType TimerRunType) {
	if self.isWaiting {
		self.log.Warnln("[启动定时器]-等待中，返回")
		return
	}
	self.runType = runType

	go func(tt *Timer) {
		tt.isWaiting = true
		for {
			select {
			case <-time.After(self.duration):
				//定时器已经停止 直接退出
				if tt.isWaiting == false {
					goto exit
				}

				go SafeCall(func(args ...interface{}) error {
					t := args[0].(*Timer)
					t.timer.OnTimer(t.userData)
					return nil
				}, tt)

				if Timer_RunLoop == runType {
					break
				} else {
					goto exit
				}
			case code := <-tt.exit:
				if code == 0 {
					break
				} else {
					tt.isWaiting = false
					tt.wg.Done()
					goto exit
				}
			}
		}
	exit:
		tt.isWaiting = false
	}(self)
}

func (self *Timer) Stop() {
	self.exitMutex.Lock()
	defer self.exitMutex.Unlock()

	if !self.isWaiting {
		return
	}

	if self.isWaiting {
		self.isWaiting = false
		self.wg.Add(1)
		self.exit <- 1
		self.wg.Wait()
	}
}

func (self *Timer) Reset() {
	if self.isWaiting && Timer_RunLoop == self.runType {
		self.exit <- 0
	}
}

func NewTimer(itimer common.ITimer, dur time.Duration, callback int) *Timer {
	return &Timer{
		exit:      make(chan int),
		timer:     itimer,
		duration:  dur,
		userData:  callback,
		isWaiting: false,
		log:       NewLogger(),
	}
}